﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;

namespace Sio.Mdm.Server
{
    [Serializable]
    public class InvocationError
    {
        #region Fields
        /// <summary>
        /// The one and only empty instance of this class
        /// </summary>
        private static readonly InvocationError Empty = new InvocationError();
        #endregion

        #region Construction
        /// <summary>
        /// Construct empty error class
        /// </summary>
        public InvocationError()
        {
        }
        /// <summary>
        /// Construct error class with passed message
        /// </summary>
        /// <param name="message">Description of error</param>
        public InvocationError(string message)
            : this(message, null)
        {
        }
        /// <summary>
        /// COnstruct error instance with message and passed exception
        /// </summary>
        /// <param name="message"></param>
        /// <param name="exception"></param>
        public InvocationError(string message, _Exception exception)
        {
            _message = message;
            _exception = exception;
        }
        /// <summary>
        /// Construct error instance with passed exception
        /// </summary>
        /// <param name="exception"></param>
        public InvocationError(_Exception exception)
            : this(null, exception)
        {
        }
        #endregion

        #region Properties

        #region Public

        #region Function
        private string _function;
        /// <summary>
        /// Get or set function where error occured [optional]
        /// </summary>
        public string Function
        {
            get
            {
                if (_function == null && _exception != null)
                {
                    return _exception.StackTrace;
                }

                return _function;
            }
            set
            {
                _function = value;
            }
        }
        #endregion

        #region Message
        private string _message;
        /// <summary>
        /// Get or set message of error
        /// </summary>
        public string Message
        {
            get
            {
                if (_message == null && _exception != null)
                {
                    return _exception.ToString();
                }

                return _message;
            }
            set
            {
                _message = value;
            }
        }
        #endregion

        #region Exception
        private _Exception _exception = null;
        /// <summary>
        /// Get or set exception that raised error
        /// </summary>
        public _Exception Exception
        {
            get
            {
                return _exception;
            }
            set
            {
                if (value != null)
                {
                    if (!(value is ISerializable))
                    {
                        throw new SerializationException("Exception object must be serializable");
                    }
                }

                _exception = value;
            }
        }
        #endregion

        #endregion

        #endregion

        #region Methods

        #region Public

        #region ToString
        /// <summary>
        /// Overriden to return instance specific informations
        /// </summary>
        /// <returns>Human readable error message</returns>
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("Message: {0}, ", String.IsNullOrEmpty(Message) ? "<not set>" : Message);
            sb.AppendFormat("Function: {0}", String.IsNullOrEmpty(Function) ? "<not set>" : Function);

            if (Exception != null)
            {
                sb.Append(", ");
                sb.Append(Exception.ToString());
            }

            return sb.ToString();
        }
        #endregion

        #region GetStackTrace
        /// <summary>
        /// Get current pregramm stack trace
        /// </summary>
        /// <returns>List of functions currently on stack</returns>
        public List<string> GetStackTrace()
        {
            string[] lines = System.Environment.StackTrace.Split('\r', '\n');
            List<string> result = new List<string>(lines.Length - 3);

            for (int i = 3; i < lines.Length; i++)
            {
                result.Add(lines[i]);
            }

            return result;
        }
        #endregion

        #endregion

        #endregion
    }
}
